"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TunnelAgent = void 0;
const http_1 = require("http");
const debug_1 = __importDefault(require("debug"));
const DEFAULT_MAX_SOCKETS = 10;
class TunnelAgent extends http_1.Agent {
    constructor(options = {}) {
        super({
            keepAlive: true,
            maxFreeSockets: 1,
        });
        this.clientId = options.clientId || '';
        this.tunnelPort = options.tunnelPort;
        this.availableSockets = [];
        this.waitingCreateConn = [];
        this.debug = (0, debug_1.default)(`lt:TunnelAgent[${this.clientId}]`);
        this.connectedSockets = 0;
        this.maxTcpSockets = options.maxTcpSockets || DEFAULT_MAX_SOCKETS;
        this.closed = false;
    }
    handleSocket(socket) {
        if (this.connectedSockets >= this.maxTcpSockets) {
            socket.destroy();
            return;
        }
        this.connectedSockets++;
        this.debug(`New socket connection [total: ${this.connectedSockets}]`);
        socket.once('close', () => {
            this.connectedSockets--;
            this.debug(`Socket closed [remaining: ${this.connectedSockets}]`);
            const idx = this.availableSockets.indexOf(socket);
            if (idx >= 0) {
                this.availableSockets.splice(idx, 1);
            }
            if (this.connectedSockets === 0) {
                this.emit('offline');
            }
        });
        if (this.connectedSockets === 1) {
            this.emit('online');
        }
        const fn = this.waitingCreateConn.shift();
        if (fn) {
            this.debug('Assigning socket to waiting connection');
            fn(null, socket);
        }
        else {
            this.debug('Adding socket to available pool');
            this.availableSockets.push(socket);
        }
    }
    stats() {
        return {
            connectedSockets: this.connectedSockets,
        };
    }
    createConnection(options, cb) {
        if (this.closed) {
            cb(new Error('已关闭'));
            return;
        }
        this.debug('创建连接');
        const sock = this.availableSockets.shift();
        if (!sock) {
            this.waitingCreateConn.push(cb);
            this.debug('等待连接: %s', this.connectedSockets);
            this.debug('可用连接: %s', this.availableSockets.length);
            return;
        }
        this.debug('socket 已分配');
        cb(null, sock);
    }
    destroy() {
        super.destroy();
    }
    async listen() {
        return {
            port: this.tunnelPort || 7002
        };
    }
}
exports.TunnelAgent = TunnelAgent;
